package io.kiki.stack.http.feign.moshi;

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.Moshi;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import okio.BufferedSource;
import okio.Okio;

import java.io.IOException;
import java.lang.reflect.Type;

public class MoshiDecoder implements Decoder {
    private final Moshi moshi;

    public MoshiDecoder(Moshi moshi) {
        this.moshi = moshi;
    }

    public MoshiDecoder() {
        this.moshi = new Moshi.Builder().build();
    }

    public MoshiDecoder(Iterable<JsonAdapter<?>> adapters) {
        this(MoshiFactory.create(adapters));
    }

    @Override
    public Object decode(Response response, Type type) throws IOException {
        JsonAdapter<Object> jsonAdapter = moshi.adapter(type);

        if (response.status() == 404 || response.status() == 204)
            return Util.emptyValueOf(type);
        if (response.body() == null)
            return null;

        try (BufferedSource source = Okio.buffer(Okio.source(response.body().asInputStream()))) {
            if (source.exhausted()) {
                return null; // empty body
            }
            return jsonAdapter.fromJson(source);
        } catch (JsonDataException e) {
            if (e.getCause() != null && e.getCause() instanceof IOException) {
                throw (IOException) e.getCause();
            }
            throw e;
        }
    }
}
